// tcp网络服务器通讯代码
#pragma once

#include <functional>
#include <unistd.h>
#include <signal.h>
#include "socket.hpp"
#include "log.hpp"
extern Log lg;

const size_t info_size = 4096;

class tcp_server
{
    using func_t = std::function<std::string(std::string &)>;

public:
    tcp_server(const func_t &call, const uint16_t port, const int backlog = default_backlog)
        : _port(port), _listen_sockfd(backlog), _call_back(call)
    {
    }
    ~tcp_server() = default;
    void init()
    {
        if (_listen_sockfd.bind(_port) < 0)
        {
            lg(Fatal, "bind sockfd error, errno:%d, errstr:%s", errno, strerror(errno));
            exit(Bind_error);
        }
        if (_listen_sockfd.listen() < 0)
        {
            lg(Fatal, "socket listen error, errno:%d, strerr:%s", errno, strerror(errno));
            exit(Listen_error);
        }
    }
    void start()
    {
        // 设置自动调用waitpid
        signal(SIGCHLD, SIG_IGN);
        signal(SIGPIPE, SIG_IGN);
        int opt = 1;
        setsockopt(_listen_sockfd.fd(), SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
        while (true)
        {
            std::string src_ip;
            uint16_t src_port;
            int sockfd = _listen_sockfd.accept(&src_ip, &src_port);
            if (sockfd < 0)
            {
                lg(Warning, "accept error, errno:%d, strerr:%s", errno, strerror(errno));
                continue;
            }
            lg(Info, "server get a new connect, ip:%s", src_ip.c_str());
            if (fork() == 0)
            {
                char inbuffer[info_size];
                // child
                _listen_sockfd.close();
                // 数据处理
                std::string send_mesg;
                while (true)
                {
                    ssize_t n = read(sockfd, inbuffer, info_size);
                    if (!n)
                    {
                        lg(Info, "%s client close connect", src_ip.c_str());
                        break;
                    }
                    else if (n < 0)
                    {
                        lg(Warning, "read error, errno:%d, strerr:%s", errno, strerror(errno));
                        errno = 0;
                        break;
                    }
                    inbuffer[n] = 0;
                    send_mesg += inbuffer;

                    // 如果是多个报文，需要处理多次
                    while (true)
                    {
                        lg(Debug, "send_mesg:\n%s", send_mesg.c_str());
                        std::string rspon = _call_back(send_mesg);
                        lg(Debug, "\nafter handle: %s\n, response: %s", send_mesg.c_str(), rspon.c_str());
                        // 如果不是一整个完整报文，直接跳过，等待下一次读取
                        if (rspon.empty())
                            break;
                        n = write(sockfd, rspon.c_str(), rspon.size());
                        if (n < 0)
                        {
                            lg(Warning, "write error, errno:%d, strerr:%s", errno, strerror(errno));
                            errno = 0;
                            exit(4);
                        }
                    }
                }
                exit(0);
            }
            // parent
            close(sockfd);
        }
    }

private:
    uint16_t _port;
    tcp_socket _listen_sockfd;
    func_t _call_back;
};